import json
from django import http
from django.core.paginator import Paginator, EmptyPage
from django.db import DatabaseError
from django.shortcuts import render, redirect
import re
import random

from django_redis import get_redis_connection

from .models import User, Address
from django.contrib.auth import login, authenticate, logout
from meiduo_mall.utils.response_code import *
# Create your views here.
from django.views import View

from django.conf import settings
from django.contrib.auth import mixins
from meiduo_mall.utils.view import LoginRequiredView
from .utls import generate_verify_email_url, check_verify_email_token, generate_access_token, check_access_token
from celery_tasks.email.tasks import send_verify_email
from goods.models import SKU
from carts.utils import merge_cart_cookie_to_redis
from orders.models import OrderInfo, OrderGoods
from celery_tasks.sms.tasks import send_sms_code

import logging

logger = logging.getLogger('django')


# 注册用户
class RegisterView(View):

    def get(self, request):
        # 提供主界面
        return render(request, "register.html")

    def post(self, request):
        # 注册逻辑
        query_dict = request.POST
        # 接受请求体表单数据
        username = query_dict.get("username")
        password = query_dict.get("password")
        password2 = query_dict.get("password2")
        mobile = query_dict.get("mobile")
        sms_code_client = query_dict.get("sms_code")
        allow = query_dict.get("allow")

        # 判断里面可迭代的元素是否为空
        # if all(username, password, password2, mobile, sms_code, allow) is False:
        if all(query_dict.dict().values()) is False:
            return http.HttpResponseForbidden("缺少必要参数")

        if not re.match(r"^[a-zA-Z0-9_-]{5,20}$", username):
            return http.HttpResponseForbidden("请输入5-20个字符的用户名")

        if not re.match(r'^[0-9a-zA-Z]{8,20}$', password):
            return http.HttpResponseForbidden("请输入8-20位密码")

        if password != password2:
            return http.HttpResponseForbidden("两次密码输入不一致")

        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseForbidden("请输入正确的手机号")
        # 短信验证后期补充
        # 创建redis连接对象
        redis_conn = get_redis_connection('verify_code')
        # 获取短信验证码
        sms_code_server = redis_conn.get('sms_%s' % mobile)
        # 让短信验证码只能用一次
        redis_conn.delete('sms_%s' % mobile)
        # 判断是否过期
        if sms_code_server is None:
            return http.HttpResponseForbidden('短信验证码过期')
        # 判断用户验证码输入是否正确
        if sms_code_client != sms_code_server.decode():
            return http.HttpResponseForbidden("短信验证码输入错误")

        # 创建一个新的用户
        user = User.objects.create_user(username=username, password=password, mobile=mobile)
        # 状态保持
        login(request, user)
        # 用户注册成功即代表登录成功
        # 响应,重定向到首页
        return redirect('/')


class UsernameCountView(View):
    # 判断用户是否重复注册
    def get(self, request, username):
        count = User.objects.filter(username=username).count()
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'count': count})


class MobileCount(View):
    def get(self, request, mobile):
        count = User.objects.filter(mobile=mobile).count()
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'count': count})


class LoginView(View):
    # 用户登陆
    def get(self, request):
        return render(request, 'login.html')

    def post(self, request):
        # 接收表单数据
        query_dict = request.POST
        username = query_dict.get('username')
        password = query_dict.get('password')
        remembered = query_dict.get('remembered')
        """
        if re.match(r'^1[3-9]\d{9}$', username):
            User.USERNAME_FIELD = 'mobile'


        # 校验
        # authenticate()用户认证的
        user = authenticate(request, username=username, password=password)
        User.USERNAME_FIELD = 'username'
        """

        # 校验
        # authenticate()用户认证的
        user = authenticate(request, username=username, password=password)
        if user is None:
            return render(request, 'login.html', {'account_errmsg': '用户名密码错误'})
        # 状态保持
        login(request, user)
        # 如果用户没有记住登陆
        # if remembered != 'on':
        # request.session.set_expiry(0)
        request.session.set_expiry((60 * 60 * 24 * 14) if remembered else 0)
        # 重定向到指定页面

        # 用户登录成功后在首页展示用户名
        response = redirect(request.GET.get('next') or '/')
        # 登录时合并购物车
        merge_cart_cookie_to_redis(request, response)
        response.set_cookie('username', user.username, max_age=settings.SESSION_COOKIE_AGE if remembered else None)

        return response


class LogoutView(View):
    # 退出登陆

    def get(self, request):
        # 清除状态
        logout(request)
        response = redirect('/login/')
        # 删除cookie中的username
        response.delete_cookie('username')
        # 重定向登陆页面
        return response


class InfoView(mixins.LoginRequiredMixin, View):
    # 用户中心
    # def get(self, request):
    #     if request.user.is_authenticated:
    #         return render(request, 'user_center_info.html')
    #     else:
    #         return redirect('/login/?next=/info/')

    def get(self, request):
        return render(request, 'user_center_info.html')


class EmailView(LoginRequiredView):
    """设置用户邮箱"""

    def put(self, request):
        # 接收数据
        json_dict = json.loads(request.body.decode())
        email = json_dict.get('email')
        # 校验
        if email is None:
            return http.HttpResponseForbidden('缺少必要参数')
        if not re.match(r'[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
            return http.HttpResponseForbidden('邮箱格式不正确')
        # 处理业务逻辑
        user = request.user
        User.objects.filter(id=user.id, email=' ').update(email=email)  # 邮箱只要设置成功了,此代码都是无效的修改
        # 生成激活url
        verify_url = generate_verify_email_url(user)
        # celery异步发邮件
        send_verify_email.delay(email, verify_url)
        # 响应
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': "OK"})


class VerifyEmailView(View):
    # 激活用户邮箱
    def get(self, request):
        # 获取查询参数中的token
        token = request.GET.get('token')
        # 校验
        if token is None:
            return http.HttpResponseForbidden('缺少token')
        # 再对token进行解密,解密后根据里面的user_id,和email查询出要激活邮箱的那个User
        user = check_verify_email_token(token)
        if user is None:
            return http.HttpResponseForbidden('token无效')
        # 修改user的email_active字段 设置为True
        user.email_active = True
        user.save()
        return redirect('/info/')


class AddressView(LoginRequiredView):
    # 收获地址

    def get(self, request):
        user = request.user
        address_qs = Address.objects.filter(user=user, is_deleted=False)
        address_list = []
        for address in address_qs:
            address_dict = {
                'id': address.id,
                'title': address.title,
                'receiver': address.receiver,
                'province_id': address.province_id,
                'province': address.province.name,
                'city_id': address.city_id,
                'city': address.city.name,
                'district_id': address.district_id,
                'district': address.district.name,
                'place': address.place,
                'mobile': address.mobile,
                'tel': address.tel,
                'email': address.email,
            }
            address_list.append(address_dict)
        # 包装模板要进行渲染的数据
        context = {
            'addresses': address_list,
            'default_address_id': user.default_address_id  # 当前用户默认收货地址id

        }
        return render(request, 'user_center_site.html', context)


class CreateAddressView(LoginRequiredView):
    """收货地址新增"""

    def post(self, request):
        user = request.user
        count = Address.objects.filter(user=user, is_deleted=False).count()
        if count >= 20:
            return http.JsonResponse({'code': RETCODE.MAXNUM, 'errmsg': "数量超限"})

        # 接收请求体数据
        json_dict = json.loads(request.body.decode())
        title = json_dict.get('title')
        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')
        # 校验
        if all([title, receiver, province_id, city_id, district_id, place, mobile]) is False:
            return http.HttpResponseForbidden('缺少必传参数')
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseForbidden("参数mobile格式不正确")
        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return http.HttpResponseForbidden("参数tel有误")
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return http.HttpResponseForbidden("参数email有误")

        try:
            address = Address.objects.create(
                user=user,
                title=title,
                receiver=receiver,
                province_id=province_id,
                city_id=city_id,
                district_id=district_id,
                place=place,
                mobile=mobile,
                tel=tel,
                email=email
            )
        except DatabaseError as e:
            logger.error(e)
            return http.HttpResponseForbidden("添加收获地址失败")
        # 如果用户还没有默认收货地址,把当前新增的收货地址设置为用户的默认收货地址
        if user.default_address is None:
            user.default_address = address
            user.save()
            # 把新增的address模型对象转换成字典,并响应给前端

        address_dict = {
            'id': address.id,
            'title': address.title,
            'receiver': address.receiver,
            'province_id': address.province_id,
            'province': address.province.name,
            'city_id': address.city_id,
            'city': address.city.name,
            'district_id': address.district_id,
            'district': address.district.name,
            'place': address.place,
            'mobile': address.mobile,
            'tel': address.tel,
            'email': address.email,
        }
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '添加收获地址成功', 'address': address_dict})


class UpdateDestroyAddressView(LoginRequiredView):
    # 修改和删除收获地址
    def put(self, request, address_id):
        """修改收货地址逻辑"""
        # 对address_id进行校验
        try:
            address = Address.objects.get(id=address_id, user=request.user, is_deleted=False)
        except Address.DoesNotExist:
            return http.HttpResponseForbidden('修改地址失败')

        # 接收请求体数据
        # json_dict = json.loads(request.body.decode())
        # title = json_dict.get('title')
        # receiver = json_dict.get('receiver')
        # province_id = json_dict.get('province_id')
        # city_id = json_dict.get('city_id')
        # district_id = json_dict.get('district_id')
        # place = json_dict.get('place')
        # mobile = json_dict.get('mobile')
        # tel = json_dict.get('tel')
        # email = json_dict.get('email')
        json_dict = json.loads(request.body.decode())
        title = json_dict.get('title')
        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')
        # 校验
        if all([title, receiver, province_id, city_id, district_id, place, mobile]) is False:
            return http.HttpResponseForbidden('缺少必传参数')
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseForbidden('参数mobile有误')
        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return http.HttpResponseForbidden('参数tel有误')
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return http.HttpResponseForbidden('参数email有误')

        try:
            # address.title = title
            # address.receiver = receiver
            # address.province_id = province_id
            # address.city_id = city_id
            # address.district_id = district_id
            # address.place = place
            # address.mobile = mobile
            # address.tel = tel
            # address.email = email
            # address.save()
            address.title = title
            address.receiver = receiver
            address.province_id = province_id
            address.city_id = city_id
            address.district_id = district_id
            address.place = place
            address.mobile = mobile
            address.tel = tel
            address.email = email
            address.save()
        except DatabaseError as e:
            logger.error(e)
            return http.HttpResponseForbidden('修改收获地址失败')
        # 把新增的address模型对象转换成字典,并响应给前端
        address_dict = {
            # 'id':address.id,
            # 'title':address.title,
            # 'receiver':address.receiver,
            # 'province_id':address.province_id,
            # 'province':address.province.name,
            # 'city_id':address.city_id,
            # 'city':address.city.name,
            # 'district_id':address.district_id,
            # 'district':address.district.name,
            # 'place':address.place,
            # 'mobile':address.mobile,
            # 'tel':address.tel,
            # 'email':address.email,
            # # "id": address.id,
            # # "title": address.title,
            # # "receiver": address.receiver,
            # # "province": address.province.name,
            # # "city": address.city.name,
            # # "district": address.district.name,
            # # "place": address.place,
            # # "mobile": address.mobile,
            # # "tel": address.tel,
            # # "email": address.email
            'id': address.id,
            'title': address.title,
            'receiver': address.receiver,
            'province_id': address.province_id,
            'province': address.province.name,
            'city_id': address.city_id,
            'city': address.city.name,
            'district_id': address.district_id,
            'district': address.district.name,
            'place': address.place,
            'mobile': address.mobile,
            'tel': address.tel,
            'email': address.email,

        }
        print(address_dict)
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '修改收货地址成功', 'address': address_dict})

    def delete(self, request, address_id):
        # 收获地址删除
        try:
            address = Address.objects.get(id=address_id, user=request.user, is_deleted=False)
        except Address.DoesNotExist:
            return http.HttpResponseForbidden('删除收获地址失败')
        address.is_deleted = True
        address.save()
        print(address)
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK'})


class DefaultAddressView(LoginRequiredView):
    # 设置用户默认收获地址
    def put(self, request, address_id):
        try:
            address = Address.objects.get(id=address_id, user=request.user, is_deleted=False)
        except Address.DoesNotExist:
            return http.HttpResponseForbidden('设置默认地址失败')

        request.user.default_address = address
        request.user.save()
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK'})


class UpdateTitleAddressView(LoginRequiredView):
    # 修改收获地址标题
    def put(self, request, address_id):
        try:
            address = Address.objects.get(id=address_id, user=request.user, is_deleted=False)
        except Address.DoesNotExist:
            return http.HttpResponseForbidden('设置默认收获地址标题失败')
        json_dict = json.loads(request.body.decode())
        title = json_dict.get('title')
        if title is None:
            return http.HttpResponseForbidden('缺少必传参数')
        address.title = title
        address.save()
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK'})


class ChangePasswordView(LoginRequiredView):
    """修改用户登录密码"""

    def get(self, request):
        return render(request, 'user_center_pass.html')

    def post(self, request):
        query_dict = request.POST
        old_pwd = query_dict.get('old_pwd')
        new_pwd = query_dict.get('new_pwd')
        new_cpwd = query_dict.get('new_cpwd')

        user = request.user
        if all([old_pwd, new_pwd, new_cpwd]) is False:
            return http.HttpResponseForbidden('缺少必传参数')

        if user.check_password(old_pwd) is False:
            return render(request, 'user_center_pass.html', {'origin_pwd_errmsg': '原始密码不正确'})
        if not re.match(r'^[0-9a-zA-Z]{8,20}$', new_pwd):
            return http.HttpResponseForbidden('请输入8-20位2长度密码')
        if new_pwd != new_cpwd:
            return http.HttpResponseForbidden('两次密码不一致')

        user.set_password(new_pwd)
        user.save()
        return redirect('/logout/')


class HistoryGoodsView(View):
    """商品浏览记录"""

    def post(self, request):
        """保存商品浏览记录"""
        # 判断用户是否登录
        if not request.user.is_authenticated:
            return http.JsonResponse({'code': RETCODE.SESSIONERR, 'errmsg': '用户未登陆'})

        # 获取请求体中的sku_id
        json_dict = json.loads(request.body.decode())
        sku_id = json_dict.get('sku_id')
        # 校验
        try:
            sku = SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return http.HttpResponseForbidden('sku_id无效')

        # 创建redis连接对象
        redis_conn = get_redis_connection('history')
        # 创建管道
        pl = redis_conn.pipeline()
        # 存储每个用户redis的唯一key
        key = 'history_%s' % request.user.id
        # 先去重
        pl.lrem(key, 0, sku_id)
        # 添加到列表的开头
        pl.lpush(key, sku_id)
        # 保留列表中前五个元素
        pl.ltrim(key, 0, 4)
        # 执行管道
        pl.execute()
        # 响应
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK'})

    def get(self, request):
        """获取用户商品浏览记录"""
        # 判断用户是否登录
        if not request.user.is_authenticated:
            return http.JsonResponse({'code': RETCODE.SESSIONERR, 'errmsg': '用户未登陆'})
        # 创建redis连接对象
        redis_conn = get_redis_connection('history')

        # 存储每个用户redis的唯一key
        key = 'history_%s' % request.user.id
        # 获取当前用户的浏览记录数据 [b'2', 1, 3, 5]
        sku_id_list = redis_conn.lrange(key, 0, -1)
        # 定义一个列表,用来装sku字典数据
        sku_list = []
        # 遍历sku_id列表,有顺序的一个一个去获取sku模型并转换成字典
        for sku_id in sku_id_list:
            sku = SKU.objects.get(id=sku_id)
            sku_list.append({
                'id': sku.id,
                'name': sku.name,
                'price': sku.price,
                'default_image_url': sku.default_image.url
            })

        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'skus': sku_list})


class AllOrderView(LoginRequiredView):
    """全部订单展示"""

    def get(self, request, id):
        user = request.user
        # order_qs = user.orderinfo_set.all()
        order_qs = OrderInfo.objects.filter(user=user).order_by('-create_time')
        if order_qs is None:
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '订单为空'})
        page_orders = []
        for order in order_qs:
            create_time = order.create_time
            order_id = order.order_id
            amount = order.total_amount
            freight = order.freight
            pay_method_name = order.pay_method
            status = order.status
            ordergood_qs = order.skus.all()
            sku_list = []
            for ordergood in ordergood_qs:
                sku = {
                    'default_image': ordergood.sku.default_image,
                    'name': ordergood.sku.name,
                    'price': ordergood.price,
                    'count': ordergood.count,
                    'amount': ordergood.price * ordergood.count,

                }
                sku_list.append(sku)
            page_orders.append({'create_time': create_time,
                                'order_id': order_id,
                                'freight': freight,
                                'total_amount': amount,
                                'sku_list': sku_list,
                                'pay_method_name': (
                                    '支付宝' if pay_method_name == OrderInfo.PAY_METHODS_ENUM['ALIPAY'] else '货到付款'),
                                'status': status,
                                'status_name': OrderInfo.ORDER_STATUS_CHOICES[status - 1][1],
                                })

        # 创建分页器：每页N条记录
        paginator = Paginator(page_orders, 5)
        # 获取每页商品数据
        try:
            page_order = paginator.page(id)
        except EmptyPage:
            return http.HttpResponseNotFound('empty page')
        # 获取列表页总页数
        total_page = paginator.num_pages
        context = {
            'page_orders': page_order,
            'page_num': id,
            'total_page': total_page,
        }

        return render(request, 'user_center_order.html', context)


class OrdersCommentView(LoginRequiredView):

    def get(self, request):
        order_id = request.GET.get('order_id')
        # try:
        #     order_info = OrderInfo.objects.get(order_id=order_id)
        # except OrderInfo.DoesNotExist:
        #     return http.HttpResponseForbidden("订单不存在")
        # ordergood_dict = ord-er_info.skus.all()

        try:
            order_goods_qs = OrderGoods.objects.get(order_id=order_id, is_commented=False)
        except OrderGoods.DoesNotExist:
            return http.HttpResponseForbidden("订单不存在")

        uncomment_goods_list = []
        for ordergood in order_goods_qs:
            uncomment_goods_list.append({
                'sku_id': ordergood.sku_id,
                'order_id': order_id,
                'name': ordergood.sku.name,
                'price': str(ordergood.price),
                'default_image_url': ordergood.sku.default_image.url,
            })


        context = {
            'uncomment_goods_list': uncomment_goods_list
        }

        return render(request, 'goods_judge.html', context)

    def post(self, request):

        json_dict = json.loads(request.body.decode())
        order_id = json_dict.get('order_id')
        sku_id = json_dict.get('sku_id')
        comment = json_dict.get('comment')
        score = json_dict.get('score')
        is_anonymous = json_dict.get('is_anonymous', False)
        if not all([order_id, sku_id, comment, score, is_anonymous]):
            return http.HttpResponseForbidden("参数不全")

        OrderGoods.objects.filter(order_id=order_id, sku_id=sku_id).update(comment=comment, score=score, is_anonymous=is_anonymous, is_commented=True)
        OrderInfo.objects.filter(order_id=order_id).update(status=5)

        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK'})


class FindPasswordView(View):
    # 找回密码
    def get(self, request):


        return render(request, 'find_password.html')


class VerifyPassWordView(View):


    def get(self, request, username):
        try:
            user = User.objects.get(username=username)
        except User.DoesNotExist:
            http.JsonResponse({'code':RETCODE.USERERR, 'errmsg':'用户名不存在'}, status=400)
        data_dict = request.GET
        text = data_dict.get('text')
        image_code_id = data_dict.get('image_code_id')

        # 创建redis连接对象
        redis_conn = get_redis_connection('verify_code')

        image_code_server = redis_conn.get(image_code_id)
        redis_conn.delete(image_code_id)
        print(image_code_server)
        print(image_code_id)
        if text.lower() != image_code_server.decode().lower():

            return http.JsonResponse({'code':RETCODE.IMAGECODEERR, 'errmsg':'图形验证码输入错误'}, status=400)
        mobile = user.mobile
        print(mobile)

        access_token = generate_access_token(user)
        return http.JsonResponse({'code':RETCODE.OK, 'errmsg':'OK', 'mobile':mobile,'access_token':access_token})



class MsgVerifyView(View):
    # 找回密码-短信验证

    def get(self, request):
        data_dict = request.GET
        access_token = data_dict.get('access_token')

        try:
            user = check_access_token(access_token)

        except User.DoesNotExist:
            return http.JsonResponse({'error':'数据错误'},status=400)
        sms_data = '%06d' % random.randint(0, 999999)
        print(sms_data)
        send_sms_code(user.mobile, sms_data)
        redis_conn = get_redis_connection('verify_code')
        redis_conn.setex(user.id, 60, sms_data)
        return http.JsonResponse({'message':'ok'})


class AccountPasswordView(View):

    def get(self, request, username):
        data_dict = request.GET
        sms_code = data_dict.get('sms_code')
        user = request.user
        redis_conn = get_redis_connection('verify_code')
        try:
            sms_code_server = redis_conn.get(user.id)
        except:
            return http.JsonResponse({'code':RETCODE.NODATAERR, 'errmsg':'验证码已过期'}, status=400)
        if sms_code != sms_code_server.decode():
            return http.JsonResponse({'code':RETCODE.NODATAERR, 'errmsg':'验证码不正确'}, status=400)
        access_token = generate_access_token(user)
        return http.JsonResponse({'code':RETCODE.OK, 'errmsg':'OK', 'user_id':user.id, 'access_token':access_token})


class UsersPasswordView(View):
    # 修改密码

    def post(self, request, id):
        data_dict = json.loads(request.body.decode())
        access_token = data_dict.get('access_token')
        password = data_dict.get('password')
        if all([id, access_token, password])is False:
            return http.HttpResponseForbidden('缺少必传参数')
        user = check_access_token(access_token)
        if not re.match(r'^[0-9a-zA-Z]{8,20}$', password):
            return http.HttpResponseForbidden("请输入8-20位密码")
        if user is None:
            return http.JsonResponse({'error':'数据错误'},status=400)
        user.set_password(password)
        user.save()
        return http.JsonResponse({'message':'ok'})





